package com.zyh.server.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zyh.server.config.Constant;
import com.zyh.server.entity.Order;
import com.zyh.server.entity.OrderDetail;
import com.zyh.server.entity.User;
import com.zyh.server.mapper.MiaoshaGoodsMapper;
import com.zyh.server.mapper.OrderDetailMapper;
import com.zyh.server.mapper.OrderMapper;
import com.zyh.server.service.MiaoshaService;
import com.zyh.server.utils.R;
import com.zyh.server.utils.RedisUtil;
import com.zyh.server.utils.UUIDUtil;
import com.zyh.server.vo.MiaoshaGoodsVO;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.Date;
import java.util.Objects;

/**
 * @Author: zyh
 * @Date: 2024-11-19-9:55
 * @Description 事务控制
 */
@Slf4j
@Service
public class MiaoshaServiceImpl implements MiaoshaService {

	//依赖注入事务管理器
	@Autowired
	private DataSourceTransactionManager transactionManager;

	@Autowired
	private MiaoshaGoodsMapper miaoshaGoodsMapper;

	@Autowired
	private RedisUtil redisUtil;

	@Autowired
	private OrderMapper orderMapper;

	@Autowired
	private OrderDetailMapper orderDetailMapper;

	//注入分布式锁客户端
	@Autowired
	private RedissonClient redissonClient;

	//阿里巴巴编程规范： 事务自动提交，出现异常需要手动回滚
	@Transactional
	@Override
	public R miaoSha(User user, Integer miaoshaGoodsId) {
		log.info("{}:进入秒杀方法!", Thread.currentThread().getName());
		//定义默认事务管理状态
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		//给事务取个名字
		def.setName("tx_miaosha");
		//事务传播行为
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		//事务状态
		TransactionStatus status = transactionManager.getTransaction(def);
		try {
			//① 设置乐观锁 key
			String lockKey = "miaosha_lock:" + miaoshaGoodsId;
			//② 创建锁
			RLock lock = redissonClient.getLock(lockKey);
			while (true) {
				//③ 尝试获取锁  100ms 尝试获取锁的等待时间  30s 锁定时间  TimeUnit时间单位
				if (lock.tryLock()) {
					try {
						log.info("{}:已经获取到锁对象,正在执行秒杀业务(扣库存,下订单)....", Thread.currentThread().getName());
						// 业务代码
						//<1> 从redis中获取秒杀商品
						Object msgObj = redisUtil.getObj(Constant.REDIS_MIAOSHA_GOODS_PREFIX + miaoshaGoodsId);
						MiaoshaGoodsVO miaoshaGoodsVO = null;
						if (msgObj == null) {
							//从mysql数据库中查询
							miaoshaGoodsVO = miaoshaGoodsMapper.selectOne(miaoshaGoodsId);
							redisUtil.saveObj(Constant.REDIS_MIAOSHA_GOODS_PREFIX + miaoshaGoodsId,
									miaoshaGoodsVO,
									Constant.REDIS_MIAOSHA_GOODS_EXPIRE);
						} else {
							miaoshaGoodsVO = new ObjectMapper().convertValue(msgObj, MiaoshaGoodsVO.class);
						}
						//<2> 获取库存
						log.info("{}获取商品库存数量:{}", Thread.currentThread().getName(), miaoshaGoodsVO.getMiaoshaStock());
						if (miaoshaGoodsVO.getMiaoshaStock() <= 0) {
							log.info(Thread.currentThread().getName() + "秒杀失败，商品秒杀完了!");
							return R.ok().setMsg("秒杀失败:商品秒杀完了!");
						}
						//<3> 库存-1 同步到mysql和redis中
						miaoshaGoodsVO = miaoshaGoodsMapper.selectOne(miaoshaGoodsId);
						redisUtil.saveObj(Constant.REDIS_MIAOSHA_GOODS_PREFIX + miaoshaGoodsId,
								miaoshaGoodsVO,
								Constant.REDIS_MIAOSHA_GOODS_EXPIRE);
						//mysql数据库中秒杀商品库存-1
						miaoshaGoodsMapper.reduceStock(miaoshaGoodsId);
						//<4> 创建订单
						//<4.1> 生成订单编号
						String orderId = UUID.randomUUID().toString().replaceAll("-", "");
						//<4.2>创建订单对象
						Order order = new Order();
						order.setId(orderId);
						order.setTotalFee(miaoshaGoodsVO.getMiaoshaPrice());
						order.setUserId(user.getId());
						order.setOrderStatus(1);
						order.setCreateTime(new Date());
						orderMapper.insert(order);

						//<4.3>创建订单项
						OrderDetail orderDetail = new OrderDetail();
						orderDetail.setOrderId(orderId);
						orderDetail.setMiaoshaGoodsId(miaoshaGoodsId);
						orderDetail.setNum(1);
						orderDetail.setName(miaoshaGoodsVO.getGoods().getName());
						orderDetail.setSpec(miaoshaGoodsVO.getGoods().getSpec());
						orderDetail.setPrice(miaoshaGoodsVO.getGoods().getPrice());
						orderDetail.setImage(miaoshaGoodsVO.getGoods().getImage());
						orderDetailMapper.insert(orderDetail);

						log.info("{}:秒杀成功,订单id:{}", Thread.currentThread().getName(), orderId);
						return R.ok().setMsg("秒杀成功").setData(orderId); //返回订单id
					} finally {
						//④ 解锁
						lock.unlock();
						log.info("{}:已经完成秒杀业务，释放锁....", Thread.currentThread().getName());
					}
				}
			}
		} catch (Exception e) {
			//出现异常，需要手动回滚事务
			transactionManager.rollback(status);
			e.printStackTrace();

		}
		return R.ok().setMsg("秒杀失败!").setData(null);
	}

	/**
	 * 获取秒杀的结果
	 * 根据用户id和秒杀商品id判断是否秒杀成功
	 * 秒杀成功状态1，秒杀失败状态-1，秒杀任务待处理状态0
	 *
	 * @param id
	 * @param miaoshaGoodsId
	 *
	 * @return
	 */
	@Override
	public R getMiaoshaResult(Integer id, Integer miaoshaGoodsId) {
		String orderId = orderMapper.checkOrder(id, miaoshaGoodsId);
		if (StrUtil.isNotEmpty(orderId)) {
			// 查询出的订单id不为空，则是秒杀成功
			return R.ok().setCode(1).setMsg("秒杀成功").setData(orderId);
		} else {
			// 查询出的订单id为空，则是秒杀失败或者待处理
			// 根据秒杀商品id查询秒杀商品的库存
			Object obj = redisUtil.getObj(Constant.REDIS_MIAOSHA_GOODS_PREFIX + miaoshaGoodsId);
			MiaoshaGoodsVO miaoshaGoodsVO = new ObjectMapper().convertValue(obj, MiaoshaGoodsVO.class);
			if (miaoshaGoodsVO.getMiaoshaStock() > 0) {
				// 代表库存还有，任务待处理
				return R.fail().setCode(0).setMsg("秒杀任务待处理");
			} else {
				// 库存<=0，说明秒杀失败
				return R.fail().setCode(-1).setMsg("秒杀失败");
			}
		}
	}
}